Fork me on GitHub

Overview

library(oidnChaRts)
geo_lines_map(data_geo_lines_map, 
              library = "leaflet")

Example data

For these examples we will use the data_geo_lines_map data.frame from the oidnChaRts library:

library(oidnChaRts)
head(data_geo_lines_map)
## # A tibble: 6 × 9
##   sender.location sender.latitude sender.longitude  receiver.location
##             <chr>           <dbl>            <dbl>              <chr>
## 1  DEU, Mockethal        50.97178         13.96013 USA, New York (NY)
## 2  DEU, Mockethal        50.97178         13.96013 USA, New York (NY)
## 3  DEU, Mockethal        50.97178         13.96013 USA, New York (NY)
## 4  DEU, Mockethal        50.97178         13.96013 USA, New York (NY)
## 5  DEU, Mockethal        50.97178         13.96013 USA, New York (NY)
## 6  DEU, Mockethal        50.97178         13.96013 USA, New York (NY)
## # ... with 5 more variables: receiver.latitude <dbl>,
## #   receiver.longitude <dbl>, date <date>, journey <chr>,
## #   number.of.letters <int>

This dataset was generated by randomly sampling a set of letters sent between European migrants to the US during the 20th Century, and adding a random offset to the date column. In general, your data should be designed to be as similar as possible to this:

  • sender.location: String describing the send location (city, house, etc)
  • sender.latitude: Decimal latitude of the send location
  • sender.longitude: Decimal longitude of the send location
  • receiver.location: String describing the send location (city, house, etc)
  • receiver.latitude: Decimal latitude of the receive locaiton
  • receiver.longitude: Decimal longitude of the receive locaiton
  • date: Date sent
  • journey: Concatenation of the send/receive locations, allows for quick de-duplication of data.
  • number.of.letters: Useful column for adding information to popups on geolines, or the line width.

Tutorial Overview

We will create interactive maps with the following data overlaid:

  • Journeys between locations will be referred to as “geolines” and are the shortest distances between the points on Earth (see great circle distance for more information).
  • End points of the journeys (send and receive locations) will be referred to as “termini”

Leaflet

Maps built with leaflet need a map to be “instantiated” and for map tiles to be set, the default map looks like this:

library(leaflet)
leaflet() %>%
  addTiles()

Leaflet isn’t able to compute great circles on its own, we therefore use the great geosphere library to compute intermediatry points along the great arcs between send and receive locations. Please note we’re using dplyr and %>% to handily extract the send/receive locations, you may need to refer to other tutorials to understand this.

library(geosphere)
library(dplyr)
geo_lines <- gcIntermediate(
  data_geo_lines_map %>%
  select(sender.longitude, sender.latitude),
  data_geo_lines_map %>%
  select(receiver.longitude, receiver.latitude),
  sp = TRUE, # SpatialLines are what Leaflet wants
  addStartEnd = TRUE, # By default this is FALSE, and would be inaccurate
  n = 50 # number of intermediate points
  )
## Individual geolines are SpatialLines, if you're interested in how they look uncomment the line below
## attributes(geo_lines[1])

The geo_lines object can now be provided to addPolylines and visualised on our map:

leaflet() %>%
  addTiles() %>%
  addPolylines(data = geo_lines)

Plotly

Plotly provides the ability to create a variety of maps, it is thoroughly advised to use only plot_geo as it is the only function in the plotly library that supports different map projects.

In order to build a map, we must first load country outlines - for which we use the map_data("world") dataset provided by ggplot2. In general, plotly objects are modified via the layout function and this is also the case for specifying map projections:

library(plotly)
plot_geo(map_data("world")) %>%
  layout(geo = list(projection = list(type = "mercator")))

Geolines are added to plotly maps via the add_segments function, however as of December 2016 there is an unfortunate issue with the library displaying additional geolines to Null Island as present. For the interested party, here is the Github issue.

sample_geo_lines <- data_geo_lines_map %>%
  sample_n(2) %>%
  select(sender.latitude,
         sender.longitude,
         receiver.latitude,
         receiver.longitude)

plot_geo() %>%
  add_segments(data = sample_geo_lines,
               x = ~sender.longitude, xend = ~receiver.longitude,
               y = ~sender.latitude, yend = ~receiver.latitude)

Using ggplot2 instead!!

Fortunately, I can try ggmaps instead!

highcharts

Highcharts provides support for mapping!

# library(highcharter)
# 
# data(worldgeojson, package = "highcharter")
# 
# highchart() %>% 
#   hc_title(text = "Violent Crime Rates by US State") %>% 
#   hc_subtitle(text = "Source: USArrests data") %>%
#   hc_add_series_map(worldgeojson, USArrests, name = "Murder arrests (per 100,000)",
#                     value = "Murder", joinBy = c("woename", "state"),
#                     dataLabels = list(enabled = TRUE,
#                                       format = '{point.properties.postalcode}')) 
# library(dplyr)
# library(viridisLite)
# library(jsonlite)
# data("USArrests", package = "datasets")
# data("usgeojson")
# 
# USArrests <- USArrests %>% 
#   mutate(state = rownames(.))
# 
# n <- 4
# colstops <- data.frame(q = 0:n/n,
#                        c = substring(viridis(n + 1, option = "A"), 0, 7)) %>% 
# list_parse2()
# 
# highchart() %>% 
#   hc_title(text = "Violent Crime Rates by US State") %>% 
#   hc_subtitle(text = "Source: USArrests data") %>% 
#   hc_add_series_map(usgeojson, USArrests, name = "Murder arrests (per 100,000)",
#                     value = "Murder", joinBy = c("woename", "state"),
#                     dataLabels = list(enabled = TRUE,
#                                       format = '{point.properties.postalcode}')) %>% 
#   hc_colorAxis(stops = colstops) %>% 
#   hc_legend(valueDecimals = 0, valueSuffix = "%") %>%
#   hc_mapNavigation(enabled = TRUE)